{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 卷积神经网络"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "epoch 0, batch 0, 损失 = 2.30691\n",
      "epoch 0, batch 100, 损失 = 0.196558\n",
      "epoch 0, batch 200, 损失 = 0.246614\n",
      "epoch 0, batch 300, 损失 = 0.0901112\n",
      "epoch 0, batch 400, 损失 = 0.0661785\n",
      "epoch 0, batch 500, 损失 = 0.019158\n",
      "epoch 1, batch 0, 损失 = 0.115891\n",
      "epoch 1, batch 100, 损失 = 0.0850154\n",
      "epoch 1, batch 200, 损失 = 0.032694\n",
      "epoch 1, batch 300, 损失 = 0.0368617\n",
      "epoch 1, batch 400, 损失 = 0.0111592\n",
      "epoch 1, batch 500, 损失 = 0.0236338\n",
      "epoch 2, batch 0, 损失 = 0.105644\n",
      "epoch 2, batch 100, 损失 = 0.0292429\n",
      "epoch 2, batch 200, 损失 = 0.0154538\n",
      "epoch 2, batch 300, 损失 = 0.0861663\n",
      "epoch 2, batch 400, 损失 = 0.00821032\n",
      "epoch 2, batch 500, 损失 = 0.00200433\n",
      "epoch 3, batch 0, 损失 = 0.0112382\n",
      "epoch 3, batch 100, 损失 = 0.0130245\n",
      "epoch 3, batch 200, 损失 = 0.0235564\n",
      "epoch 3, batch 300, 损失 = 0.0563519\n",
      "epoch 3, batch 400, 损失 = 0.00335572\n",
      "epoch 3, batch 500, 损失 = 0.00445928\n",
      "epoch 4, batch 0, 损失 = 0.0196497\n",
      "epoch 4, batch 100, 损失 = 0.00330122\n",
      "epoch 4, batch 200, 损失 = 0.0172663\n",
      "epoch 4, batch 300, 损失 = 0.00805396\n",
      "epoch 4, batch 400, 损失 = 0.00689415\n",
      "epoch 4, batch 500, 损失 = 0.00281626\n",
      "测试数据准确率: 98.8%\n"
     ]
    }
   ],
   "source": [
    "import torch\n",
    "import torch.utils.data\n",
    "import torch.nn\n",
    "import torch.optim\n",
    "import torchvision.datasets\n",
    "import torchvision.transforms\n",
    "\n",
    "# 数据读取\n",
    "train_dataset = torchvision.datasets.MNIST(root='./data/mnist',\n",
    "        train=True, transform=torchvision.transforms.ToTensor(),\n",
    "        download=True)\n",
    "test_dataset = torchvision.datasets.MNIST(root='./data/mnist',\n",
    "        train=False, transform=torchvision.transforms.ToTensor(),\n",
    "        download=True)\n",
    "\n",
    "batch_size = 100\n",
    "train_loader = torch.utils.data.DataLoader(\n",
    "        dataset=train_dataset, batch_size=batch_size)\n",
    "test_loader = torch.utils.data.DataLoader(\n",
    "        dataset=test_dataset, batch_size=batch_size)\n",
    "\n",
    "# 搭建网络结构\n",
    "class Net(torch.nn.Module):\n",
    "    \n",
    "    def __init__(self):\n",
    "        super(Net, self).__init__()\n",
    "        self.conv1 = torch.nn.Sequential(\n",
    "                torch.nn.Conv2d(1, 64, kernel_size=3, padding=1),\n",
    "                torch.nn.ReLU(),\n",
    "                torch.nn.Conv2d(64, 128, kernel_size=3, padding=1),\n",
    "                torch.nn.ReLU(),\n",
    "                torch.nn.MaxPool2d(stride=2, kernel_size=2))\n",
    "        self.dense = torch.nn.Sequential(\n",
    "                torch.nn.Linear(128 * 14 * 14, 1024),\n",
    "                torch.nn.ReLU(),\n",
    "                torch.nn.Dropout(p=0.5),\n",
    "                torch.nn.Linear(1024, 10))\n",
    "        \n",
    "    def forward(self, x):\n",
    "        x = self.conv1(x)\n",
    "        x = x.view(-1, 128 * 14 * 14)\n",
    "        x = self.dense(x)\n",
    "        return x\n",
    "\n",
    "net = Net()\n",
    "\n",
    "criterion = torch.nn.CrossEntropyLoss()\n",
    "optimizer = torch.optim.Adam(net.parameters()) \n",
    "\n",
    "# 训练\n",
    "num_epochs = 5\n",
    "for epoch in range(num_epochs):\n",
    "    for idx, (images, labels) in enumerate(train_loader):\n",
    "        optimizer.zero_grad()\n",
    "        preds = net(images)\n",
    "        loss = criterion(preds, labels)\n",
    "        loss.backward()\n",
    "        optimizer.step()\n",
    "        \n",
    "        if idx % 100 == 0:\n",
    "            print('epoch {}, batch {}, 损失 = {:g}'.format(\n",
    "                    epoch, idx, loss.item()))\n",
    "\n",
    "# 测试\n",
    "correct = 0\n",
    "total = 0\n",
    "for images, labels in test_loader:\n",
    "    preds = net(images)\n",
    "    predicted = torch.argmax(preds, 1)\n",
    "    total += labels.size(0)\n",
    "    correct += (predicted == labels).sum().item()\n",
    "    \n",
    "accuracy = correct / total\n",
    "print('测试数据准确率: {:.1%}'.format(accuracy))"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
